/*
 * Copyright (c) 2006 Your Corporation. All Rights Reserved.
 */
package org.ivytools.repository.svn;

import fr.jayasoft.ivy.repository.AbstractRepository;
import fr.jayasoft.ivy.repository.TransferEvent;
import fr.jayasoft.ivy.util.CopyProgressEvent;
import fr.jayasoft.ivy.util.CopyProgressListener;
import fr.jayasoft.ivy.util.FileUtil;
import fr.jayasoft.ivy.util.Message;
import org.tigris.subversion.svnclientadapter.ISVNClientAdapter;
import org.tigris.subversion.svnclientadapter.SVNClientAdapterFactory;
import org.tigris.subversion.svnclientadapter.SVNClientException;
import org.tigris.subversion.svnclientadapter.javasvn.JavaSvnClientAdapterFactory;
import org.tigris.subversion.svnclientadapter.commandline.CmdLineClientAdapterFactory;
import org.tigris.subversion.svnclientadapter.javahl.JhlClientAdapterFactory;

import java.io.File;
import java.io.IOException;
import java.util.List;

/**
 * An Ivy representation of a SVN repository.
 *
 * @author shaug
 * @since Jan 17, 2006 11:52:24 PM
 */
public class SvnRepository extends AbstractRepository {
    private ISVNClientAdapter client;
    private String clientType;
    private String username;
    private String password;

    static {
        try {
            JavaSvnClientAdapterFactory.setup();
        } catch (Throwable e) {
            Message.debug("Unable to load javasvn adapter: " + e.getMessage());
        }
        try {
            JhlClientAdapterFactory.setup();
        } catch (Throwable e) {
            Message.debug("Unable to load javahl adapter: " + e.getMessage());
        }
        try {
            CmdLineClientAdapterFactory.setup();
        } catch (Exception e) {
            Message.debug("Unable to load commandline adapter: " + e.getMessage());
        }
    }


    public ISVNClientAdapter getClient() {
        if (client == null) {
            String type = clientType;
            if (type == null) {
                try {
                    type = SVNClientAdapterFactory.getPreferredSVNClientType();
                } catch (SVNClientException e) {
                    throw new IllegalArgumentException("Unable to create client from specified type: " + type, e);
                }
            }
            Message.debug("Creating repository of type: " + type);
            client = SVNClientAdapterFactory.createSVNClient(type);
            if (username != null) {
                client.setUsername(username);
            }
            if (password != null) {
                client.setPassword(password);
            }
        }
        return client;
    }

    private final CopyProgressListener progress = new CopyProgressListener() {
        public void start(CopyProgressEvent evt) {
            fireTransferStarted();
        }
        public void progress(CopyProgressEvent evt) {
            fireTransferProgress(evt.getBuffer(), evt.getReadBytes());
        }
        public void end(CopyProgressEvent evt) {
            fireTransferCompleted(evt.getBuffer(), evt.getReadBytes());
        }
    };

    public SvnResource getResource(String source) throws IOException {
        return new SvnResource(getClient(), source);
    }

    public void get(String source, File destination) throws IOException {
        SvnResource resource = getResource(source);
        fireTransferInitiated(resource, TransferEvent.REQUEST_GET);
        try {
            FileUtil.copy(resource.getInputStream(), destination, progress);
        } catch (IOException ex) {
            fireTransferError(ex);
            throw ex;
        } catch (RuntimeException ex) {
            fireTransferError(ex);
            throw ex;
        }
    }

    public void put(File file, String string, boolean b) throws IOException {
        throw new UnsupportedOperationException("SVN repository is not able to put files for the moment");
    }

    public List list(String parent) throws IOException {
        return getResource(parent).getDirEntries();
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setClientType(String clientType) {
        this.clientType = clientType;
    }
}
